<template>
  <div class="heheh">
    <canvas id="canvas"></canvas>
  </div>
</template>

<script>
export default {
  data() {
    return {}
  },
  methods: {},
  mounted() {
    console.log(11)

    // when animating on canvas, it is best to use requestAnimationFrame instead of setTimeout or setInterval
    // not supported in all browsers though and sometimes needs a prefix, so we need a shim
    window.requestAnimFrame = (function() {
      return (
        window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        function(callback) {
          window.setTimeout(callback, 1000 / 60)
        }
      )
    })()

    // now we will setup our basic variables for the demo
    var canvas = document.getElementById('canvas'),
      ctx = canvas.getContext('2d'),
      // full screen dimensions
      cw = window.innerWidth,
      ch = window.innerHeight,
      // firework collection
      fireworks = [],
      // particle collection
      particles = [],
      // starting hue
      hue = 120,
      // when launching fireworks with a click, too many get launched at once without a limiter, one launch per 5 loop ticks
      limiterTotal = 5,
      limiterTick = 0,
      // this will time the auto launches of fireworks, one launch per 80 loop ticks
      timerTotal = 80,
      timerTick = 0,
      mousedown = false,
      // mouse x coordinate,
      mx,
      // mouse y coordinate
      my

    // set canvas dimensions
    canvas.width = cw
    canvas.height = ch

    // now we are going to setup our function placeholders for the entire demo

    // get a random number within a range
    function random(min, max) {
      return Math.random() * (max - min) + min
    }

    // calculate the distance between two points
    function calculateDistance(p1x, p1y, p2x, p2y) {
      var xDistance = p1x - p2x,
        yDistance = p1y - p2y
      return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2))
    }

    // create firework
    function Firework(sx, sy, tx, ty) {
      // actual coordinates
      this.x = sx
      this.y = sy
      // starting coordinates
      this.sx = sx
      this.sy = sy
      // target coordinates
      this.tx = tx
      this.ty = ty
      // distance from starting point to target
      this.distanceToTarget = calculateDistance(sx, sy, tx, ty)
      this.distanceTraveled = 0
      // track the past coordinates of each firework to create a trail effect, increase the coordinate count to create more prominent trails
      this.coordinates = []
      this.coordinateCount = 3
      // populate initial coordinate collection with the current coordinates
      while (this.coordinateCount--) {
        this.coordinates.push([this.x, this.y])
      }
      this.angle = Math.atan2(ty - sy, tx - sx)
      this.speed = 2
      this.acceleration = 1.05
      this.brightness = random(50, 70)
      // circle target indicator radius
      this.targetRadius = 1
    }

    // update firework
    Firework.prototype.update = function(index) {
      // remove last item in coordinates array
      this.coordinates.pop()
      // add current coordinates to the start of the array
      this.coordinates.unshift([this.x, this.y])

      // cycle the circle target indicator radius
      if (this.targetRadius < 8) {
        this.targetRadius += 0.3
      } else {
        this.targetRadius = 1
      }

      // speed up the firework
      this.speed *= this.acceleration

      // get the current velocities based on angle and speed
      var vx = Math.cos(this.angle) * this.speed,
        vy = Math.sin(this.angle) * this.speed
      // how far will the firework have traveled with velocities applied?
      this.distanceTraveled = calculateDistance(this.sx, this.sy, this.x + vx, this.y + vy)

      // if the distance traveled, including velocities, is greater than the initial distance to the target, then the target has been reached
      if (this.distanceTraveled >= this.distanceToTarget) {
        createParticles(this.tx, this.ty)
        // remove the firework, use the index passed into the update function to determine which to remove
        fireworks.splice(index, 1)
      } else {
        // target not reached, keep traveling
        this.x += vx
        this.y += vy
      }
    }

    // draw firework
    Firework.prototype.draw = function() {
      ctx.beginPath()
      // move to the last tracked coordinate in the set, then draw a line to the current x and y
      ctx.moveTo(this.coordinates[this.coordinates.length - 1][0], this.coordinates[this.coordinates.length - 1][1])
      ctx.lineTo(this.x, this.y)
      ctx.strokeStyle = 'hsl(' + hue + ', 100%, ' + this.brightness + '%)'
      ctx.stroke()

      ctx.beginPath()
      // draw the target for this firework with a pulsing circle
      ctx.arc(this.tx, this.ty, this.targetRadius, 0, Math.PI * 2)
      ctx.stroke()
    }

    // create particle
    function Particle(x, y) {
      this.x = x
      this.y = y
      // track the past coordinates of each particle to create a trail effect, increase the coordinate count to create more prominent trails
      this.coordinates = []
      this.coordinateCount = 5
      while (this.coordinateCount--) {
        this.coordinates.push([this.x, this.y])
      }
      // set a random angle in all possible directions, in radians
      this.angle = random(0, Math.PI * 2)
      this.speed = random(1, 10)
      // friction will slow the particle down
      this.friction = 0.95
      // gravity will be applied and pull the particle down
      this.gravity = 1
      // set the hue to a random number +-20 of the overall hue variable
      this.hue = random(hue - 20, hue + 20)
      this.brightness = random(50, 80)
      this.alpha = 1
      // set how fast the particle fades out
      this.decay = random(0.015, 0.03)
    }

    // update particle
    Particle.prototype.update = function(index) {
      // remove last item in coordinates array
      this.coordinates.pop()
      // add current coordinates to the start of the array
      this.coordinates.unshift([this.x, this.y])
      // slow down the particle
      this.speed *= this.friction
      // apply velocity
      this.x += Math.cos(this.angle) * this.speed
      this.y += Math.sin(this.angle) * this.speed + this.gravity
      // fade out the particle
      this.alpha -= this.decay

      // remove the particle once the alpha is low enough, based on the passed in index
      if (this.alpha <= this.decay) {
        particles.splice(index, 1)
      }
    }

    // draw particle
    Particle.prototype.draw = function() {
      ctx.beginPath()
      // move to the last tracked coordinates in the set, then draw a line to the current x and y
      ctx.moveTo(this.coordinates[this.coordinates.length - 1][0], this.coordinates[this.coordinates.length - 1][1])
      ctx.lineTo(this.x, this.y)
      ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')'
      ctx.stroke()
    }

    // create particle group/explosion
    function createParticles(x, y) {
      // increase the particle count for a bigger explosion, beware of the canvas performance hit with the increased particles though
      var particleCount = 30
      while (particleCount--) {
        particles.push(new Particle(x, y))
      }
    }

    // main demo loop
    function loop() {
      // this function will run endlessly with requestAnimationFrame
      requestAnimFrame(loop)

      // increase the hue to get different colored fireworks over time
      hue += 0.5

      // normally, clearRect() would be used to clear the canvas
      // we want to create a trailing effect though
      // setting the composite operation to destination-out will allow us to clear the canvas at a specific opacity, rather than wiping it entirely
      ctx.globalCompositeOperation = 'destination-out'
      // decrease the alpha property to create more prominent trails
      ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'
      ctx.fillRect(0, 0, cw, ch)
      // change the composite operation back to our main mode
      // lighter creates bright highlight points as the fireworks and particles overlap each other
      ctx.globalCompositeOperation = 'lighter'

      var text = '新 年 快 乐'
      ctx.font = '50px sans-serif'
      var textData = ctx.measureText(text)
      ctx.fillStyle = 'rgba(' + parseInt(random(0, 255)) + ',' + parseInt(random(0, 255)) + ',' + parseInt(random(0, 255)) + ',0.3)'
      ctx.fillText(text, cw / 2 - textData.width / 2, ch / 2)

      // loop over each firework, draw it, update it
      var i = fireworks.length
      while (i--) {
        fireworks[i].draw()
        fireworks[i].update(i)
      }

      // loop over each particle, draw it, update it
      var i = particles.length
      while (i--) {
        particles[i].draw()
        particles[i].update(i)
      }

      // launch fireworks automatically to random coordinates, when the mouse isn't down
      if (timerTick >= timerTotal) {
        if (!mousedown) {
          // start the firework at the bottom middle of the screen, then set the random target coordinates, the random y coordinates will be set within the range of the top half of the screen

          for (var h = 0; h < 50; h++) {
            fireworks.push(new Firework(cw / 2, ch / 2, random(0, cw), random(0, ch)))
          }

          timerTick = 0
        }
      } else {
        timerTick++
      }

      // limit the rate at which fireworks get launched when mouse is down
      if (limiterTick >= limiterTotal) {
        if (mousedown) {
          // start the firework at the bottom middle of the screen, then set the current mouse coordinates as the target
          fireworks.push(new Firework(cw / 2, ch / 2, mx, my))
          limiterTick = 0
        }
      } else {
        limiterTick++
      }
    }

    // mouse event bindings
    // update the mouse coordinates on mousemove
    canvas.addEventListener('mousemove', function(e) {
      mx = e.pageX - canvas.offsetLeft
      my = e.pageY - canvas.offsetTop
    })

    // toggle mousedown state and prevent canvas from being selected
    canvas.addEventListener('mousedown', function(e) {
      e.preventDefault()
      mousedown = true
    })

    canvas.addEventListener('mouseup', function(e) {
      e.preventDefault()
      mousedown = false
    })

    // once the window loads, we are ready for some fireworks!
    this.$nextTick(function() {
      loop()
      console.log('加载完毕')
    })
  }
}
</script>

<style lang="less" scoped>
#canvas {
  cursor: crosshair;
  display: block;
}
.heheh {
  width: 100%;
  height: 100%;
}
</style>
